Example 4 - Scene extensions
This example showcases how to extend the scene with custom Three.js components.
Reference: Example 4 - Scene extensions
Key Features
- Integration with React Three Fiber
- Custom animated 3D object (spinning cube)
- Viewport-specific rendering
- Scene extension architecture
- Multiple viewports with selective content
Code Example
Below is an example implementation of a spinning cube that is rendered selectively in specific viewports. The cube rotates continuously and demonstrates how to extend the scene with custom Three.js components.
import { Stack } from "@mui/system";
import { useFrame, useThree } from "@react-three/fiber";
import { useRef } from "react";
import type { Mesh } from "three";
import { PlySample } from "../../data/scans";
import { useViewId } from "../../helpers/ViewContext";
import { Viewport } from "../../ui/Viewport";
import { Viewer } from "../../Viewer";
import { PerspectiveView } from "../../views/PerspectiveView";
// Use a relative path string instead of importing the file content
const factoryPath = PlySample["FACTORY"].url;
export function SpinningCube() {
const meshRef = useRef<Mesh>(null!);
const viewId = useViewId();
const invalidate = useThree((s) => s.invalidate);
// Rotate the cube on each frame
useFrame((state, delta) => {
if (meshRef.current) {
meshRef.current.rotation.x += delta;
meshRef.current.rotation.y += delta;
// Invalidate the scene to update the view - otherwise the view will not update.
// Try removing this line to see the difference.
invalidate();
}
});
// Only render the cube in the "3d-2" view, not in the "3d" view.
if (viewId === "3d") return null;
return (
<mesh ref={meshRef}>
<boxGeometry args={[30, 30, 30]} />
<meshStandardMaterial color="orange" />
</mesh>
);
}
function App() {
return (
<Viewer
sx={{
background: "transparent",
position: "absolute",
inset: 0,
zIndex: 0,
}}
sceneExtension={
<>
{/* Add the SpinningCube component to the scene */}
{/* Please note - the extensions here will be added to all views. */}
{/* If you want to add it to a specific view, you need to check the viewId inside the component. */}
{/* See the SpinningCube component for an example. */}
<SpinningCube />
</>
}
objects={{
example: {
url: factoryPath,
excludeInViews: ["3d-2"],
},
}}
>
<Stack sx={{ width: "100%", height: "100%", flexDirection: "row" }}>
<Viewport props={{}} name={"3d"} component={PerspectiveView} />
<Viewport props={{}} name={"3d-2"} component={PerspectiveView} />
</Stack>
</Viewer>
);
}
export default App;
Explanation
-
SpinningCube Component: This component creates a spinning cube using Three.js. It uses
useFrameto update the cube's rotation on each frame and selectively renders the cube based on theviewId. -
Viewer Component: The
Viewercomponent is extended with theSpinningCubecomponent. ThesceneExtensionprop allows adding custom components to the scene. -
Multiple Viewports: Two viewports (
3dand3d-2) are defined. The spinning cube is only rendered in the3d-2viewport, demonstrating viewport-specific rendering. -
Scene Invalidation: The
invalidatefunction ensures the scene updates correctly when the cube rotates.
This example highlights how to extend and customize scenes in a React Three Fiber application.